// 导入 threejs
import * as THREE from 'three'
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 导入lil.gui
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'

// 创建场景
const scene= new THREE.Scene()

// 创建相机
const camera = new THREE.PerspectiveCamera(
  45,  // 视角
  window.innerWidth / window.innerHeight,
  0.1,  // 近平面
  1000   // 远平面
)

// 创建渲染器
const renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)   // 整屏渲染，canvas为基础

// 将画布添加到页面标签里
document.body.appendChild(renderer.domElement)


// 创建几何体，立方体
const geometry = new THREE.BoxGeometry(1, 1, 1)
// 创建材质
const material = new THREE.MeshBasicMaterial({color: 0x00ff00})  // 设置材质颜色为绿色
// 创建网格，展现具体的物体了，绿色的几何体
const cube = new THREE.Mesh(geometry, material)

// position是局部坐标，相对父元素的
// 给物体设置位置, 可以直接设置
// cube.position.x = 2  
// 也可以调用方法，可以做计算， position是三维向量属性
cube.position.set(4, 1, 0)

// 设置物体 的放大, scale属性是设置缩放的，也是三维向量属性  vector3, 相对父元素的
cube.scale.set(2, 3, 2)  // x,y,x轴上都放大两倍

// 旋转 是 rotation 属性，这是一个 euler(欧拉角)属性的，通过指定轴顺序和各个轴上指定旋转角度来旋转一个物体
// 绕 x 轴旋转
cube.rotation.x = Math.PI/4  // 旋转 45度


// 添加一个父元素
const parentMaterial = new THREE.MeshBasicMaterial({color: 0xff0000})  // 设置为红色材质
// 父元素材质展现线框模式
parentMaterial.wireframe = true
const parentCube = new THREE.Mesh(geometry, parentMaterial)
parentCube.position.set(-2, 0, 0)   // 设置父元素位置
// 给父元素也放大
// parentCube.scale.set(3, 2, 1)
// 父元素也旋转
parentCube.rotation.x = Math.PI / 4   // 旋转45度

// 将网格添加到场景中
// scene.add(cube)
// 将子元素添加到父元素中，父元素在加入场景
parentCube.add(cube)
scene.add(parentCube)

// 添加世界坐标辅助器，x,y,z轴的辅助线
const axesHelper = new THREE.AxesHelper(5)   // 并设置线段的长度为5
// 添加到场景当中
scene.add(axesHelper)

// 设置相机位置
// camera.position.z = 5   // 设置在哪个轴， x, y, z 这里设置z轴
// camera.lookAt(0, 0, 0)    // 设置相机看向什么位置，看向原点位置

// 为了看到z轴的线，调整相机位置
camera.position.z = 5   
camera.position.x = 3
camera.position.y = 2
camera.lookAt(0, 0, 0)  


// 渲染
// renderer.render(scene, camera)

// 添加轨道控制器， 先在上面导入
const controls = new OrbitControls(camera, renderer.domElement)   // renderer.domElement这个表示监听的元素是 canvas 元素， 渲染的标签
// const controls = new OrbitControls(camera, document.body)   // 监听body
// 设置带阻尼的惯性，阻尼感
controls.enableDamping = true         // 开启
// 设置阻尼系数
// controls.dampingFactor = 0.01          // 越小阻尼感越大
controls.dampingFactor = 0.5
// controls.autoRotate = true         // 自转，自动绕着目标旋转， 开启这个必须要使用 controls方法

// 做一个渲染函数， 不断渲染
function animate() {
  controls.update()    // 渲染的时候也要每次更新控制器
  requestAnimationFrame(animate)       // 相当于定时器，不断调用，一直渲染
  // 旋转功能
  // cube.rotation.x += 0.01
  // cube.rotation.y += 0.01
  // 渲染
  renderer.render(scene, camera)
}
animate()

// 监听窗口变化
window.addEventListener("resize", () => {
  // 重置渲染器宽高比
  renderer.setSize(window.innerWidth, window.innerHeight)
  // 重置相机宽高比
  camera.aspect = window.innerWidth / window.innerHeight
  // 更新相机投影矩阵 ， 一定要加
  camera.updateProjectionMatrix()
})


let debugEvent = {
  // 全屏函数
  Fullscreen: function() {
    renderer.domElement.requestFullscreen()
  },
  exitFullscreen: function() {
    renderer.domElement.exitFullscreen()
  }
}

// 创建GUI
const gui = new GUI()
// gui.add(debugEvent, "Fullscreen")        // 会在界面上自动创建调试的按钮
gui.add(debugEvent, "Fullscreen").name("全屏")  // 设置名字
gui.add(debugEvent, "exitFullscreen").name("退出全屏")

// 控制立方体的位置
// gui.add(cube.position, 'x', -10, 10).name("物体x轴位置")
gui.add(cube.position, 'x').min(-10).max(10).step(1).name("物体x轴位置")   // 链式操作，加步长
gui.add(cube.position, 'y').min(-10).max(10).step(1).name("物体y轴位置")   // 链式操作，加步长
gui.add(cube.position, 'z').min(-10).max(10).step(1).name("物体z轴位置")   // 链式操作，加步长
// 分块，建文件夹
let folder = gui.addFolder("父元素位置")
// folder.add(parentCube.position, 'x').min(-10).max(10).step(1).name("x轴位置")
// folder.add(parentCube.position, 'y').min(-10).max(10).step(1).name("y轴位置")
// folder.add(parentCube.position, 'z').min(-10).max(10).step(1).name("z轴位置")

folder.add(parentCube.position, 'x').min(-10).max(10).step(1).name("x轴位置")
      .onChange((val) => {
        // 监听位置改变的事件（拖拽时触发）
        console.log("立方体x轴位置", val);
      })
folder.add(parentCube.position, 'y').min(-10).max(10).step(1).name("y轴位置")
      .onFinishChange((val) => {
        // 监听位置改变结束时的事件（拖拽完触发）
        console.log("立方体y轴位置", val);
      })
folder.add(parentCube.position, 'z').min(-10).max(10).step(1).name("z轴位置")

// 转换父元素材质为实体
gui.add(parentMaterial, "wireframe").name("父元素线框模式")

// 设置物体材质颜色变换
let colorParams = {
  cubeColor: '#ff0000'
}
gui.addColor(colorParams, 'cubeColor').name("物体颜色")        // 添加颜色选择器
  .onChange(val => {
    cube.material.color.set(val)
  })
    